/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = informix_request.c                                            */
/*  NOTE      = TDS协议解析                                                   */
/*  DATE      = 2014/05/27 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "informix_core.h"
#include "informix_common.h"
#include "informix_sql_type.h"

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  skip type info
*  ARGS     :  p_st_private(MSSQL私有信息)
            :  ui_count(个数)
            :  i_param_flg(是否是parameter))
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
static int __informix_skip_type_info(L7session_informix_private *p_st_private
                                      , unsigned int ui_count
                                      , int i_param_flg
                                      , int i_bool_flg)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_informix *p_st_session = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    while (ui_count--)
    {
        if (i_bool_flg == FR_YES)
        {
            i_ret = informix_skip_bytes(p_st_data, 1);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                return i_ret;
            }
            i_ret = informix_skip_2byte_padded(p_st_data);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip padded data!\n");
                return i_ret;
            }
        }

        i_ret = informix_skip_bytes(p_st_data, 1 + 2 + 4);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip bytes failed!\n");
            return i_ret;
        }
        if (p_st_session->arr_ver_info[INFORMIX_902_IDX])
        {
            i_ret = informix_skip_bytes(p_st_data, 4 + 2 + 2);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                return i_ret;
            }
            if (i_param_flg == FR_YES
                && p_st_session->arr_ver_info[INFORMIX_MULTIPLEUDROUTSUPPORTED_IDX])
            {
                i_ret = informix_skip_bytes(p_st_data, 2);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    frdbg("skip bytes failed!\n");
                    return i_ret;
                }
            }
        }
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析DESCRIBE
*  ARGS     :  p_st_private(MSSQL私有信息)
            :  i_bool_flg(boolean)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int informix_parse_describe_comm(L7session_informix_private *p_st_private
                                 , int i_bool_flg)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    uint16_t u16_rows = 0;
    uint16_t u16_data_type = 0;
    uint16_t u16_value = 0;
    uint32_t u32_encoded_len = 0;
    int i_nullable_flg = 0;
    int i_data_type = 0;
    unsigned int ui_precision = 0;
    unsigned int ui_scale = 0;
    unsigned int ui_len = 0;
    Frlist_node *p_st_node = NULL;
    Sql_metadata_info *p_st_metadata = NULL;
    L7_resp_informix *p_st_resp = p_st_private->p_st_resp;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 长度check */
    if (bytebuff_remaining(p_st_data) < 2)
    {
        frdbg("Need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    /* get cloum row count */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_rows, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("get rows data!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    if (p_st_sess->arr_ver_info[INFORMIX_NAMEDPARAMETERSSUPPORTED_IDX]
        && u16_rows != 0)
    {
        /* 长度check */
        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("Need more data!\n");
            return APM_L7_ANALYZE_TODO;
        }
        /* get cloum row count */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_value, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get value data!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        if (i_bool_flg == FR_NO && u16_value & 0x01)
        {
            i_ret = informix_skip_bytes(p_st_data, 2);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                return i_ret;
            }
        }
    }

    while (u16_rows--)
    {
        if (u16_value & 0x01)
        {
            i_ret = informix_skip_bytes(p_st_data, 1);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                frlist_remove_all(&p_st_resp->st_metadata_column
                                  , frdb_metadata_node_free);
                return i_ret;
            }
            i_ret = informix_skip_2byte_padded(p_st_data);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip padded failed!\n");
                frlist_remove_all(&p_st_resp->st_metadata_column
                                  , frdb_metadata_node_free);
                return i_ret;
            }
        }

        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("need more data!\n");
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            return APM_L7_ANALYZE_TODO;
        }
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_data_type, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get data type data!\n");
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            return APM_L7_ANALYZE_FAIL;
        }
        if ((u16_data_type & 0x100) > 0)
        {
           i_nullable_flg = FR_YES;
        }
        i_data_type = u16_data_type & (0x00FF);

        /* skip 4bytes */
        if (bytebuff_remaining(p_st_data) < 4)
        {
            frdbg("need more data!\n");
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            return APM_L7_ANALYZE_TODO;
        }
        bytebuff_skip(p_st_data, 4);

        /* skip ExtendedId and ExtendedOwnerName */
        i_ret = informix_skip_2byte_padded(p_st_data);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip ExtendedId and ExtendedOwnerName failed!\n");
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            return i_ret;
        }
        i_ret = informix_skip_2byte_padded(p_st_data);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip padded faield!\n");
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            return i_ret;
        }
        /* skip source type */
        if (bytebuff_remaining(p_st_data) < 2 + 2 + 4 + 4)
        {
            frdbg("need more data!\n");
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            return APM_L7_ANALYZE_TODO;
        }
        bytebuff_skip(p_st_data, 2 + 2 + 4);
        /* get Encoded Length  */
        i_ret = bytebuff_get_int(p_st_data, 4, &u32_encoded_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get Encoded Length failed!\n");
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            return APM_L7_ANALYZE_FAIL;
        }
        if (i_bool_flg == FR_YES)
        {
            i_ret = informix_skip_bytes(p_st_data, 2);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                frlist_remove_all(&p_st_resp->st_metadata_column
                                  , frdb_metadata_node_free);
                return i_ret;
            }
        }


        switch (i_data_type)
        {
            case INFORMIX_TYPE_DECIMAL:
            case INFORMIX_TYPE_MONEY:
                ui_precision = u32_encoded_len >> 8 & 0xFF;
                ui_scale = u32_encoded_len & 0xFF;

            case INFORMIX_TYPE_DATETIME:
            case INFORMIX_TYPE_INTERVAL:
                ui_len = ((u32_encoded_len >> 8 & 0xFF)
                         + (u32_encoded_len & 0xFF & 0x1) + 3) / 2;
                break;

            default:
                ui_len = u32_encoded_len;
                break;
        }

        /* 创建节点 */
        p_st_metadata = (Sql_metadata_info *)frmalloc(sizeof(Sql_metadata_info));
        if (p_st_metadata == NULL)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column, frdb_metadata_node_free);
            return APM_L7_ANALYZE_FAIL;
        }
        memset(p_st_metadata, 0x0, sizeof(Sql_metadata_info));
        p_st_metadata->i_data_type = i_data_type;
        p_st_metadata->ui_precision = ui_precision;
        p_st_metadata->ui_scale = ui_scale;
        p_st_metadata->ui_len = ui_len;
        p_st_metadata->i_isnullbydescribe = i_nullable_flg;
        p_st_node = frlist_node_create(p_st_metadata);
        if (p_st_node == NULL)
        {
            frfree(p_st_metadata);
            frlist_remove_all(&p_st_resp->st_metadata_column, frdb_metadata_node_free);
            return APM_L7_ANALYZE_FAIL;
        }
        frlist_push(&p_st_resp->st_metadata_column, p_st_node);
    }

    return APM_L7_ANALYZE_SUCC;

}

/*******************************************************************************
*  FUNC     :  上报响应结果信息
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_private(MSSQL私有信息)
            :  p_st_hash_report((Frhash_header *))
            :  i_sql_rpc(MSSQL_RPC/MSSQL_SQL)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
static int __informix_report_resp(Conntrack *p_st_conn
                                  , L7session_informix_private *p_st_private
                                  , Frhash_header *p_st_hash_report)
{
    int i_ret = FR_SUCC;
    Frreport_body_data *p_st_report_body = NULL;
    L7_req_informix *p_st_req = p_st_private->p_st_req;
    L7_resp_informix *p_st_resp = p_st_private->p_st_resp;
    Sql_resultset *p_st_resultset = p_st_req->p_st_resultset;
    Sql_statement *p_st_statement = p_st_req->p_st_statement;

    if (p_st_statement == NULL || p_st_resultset == NULL)
    {
        frdbg("p_st_statement or p_st_resultset is null\n");
        return APM_L7_ANALYZE_SUCC;
    }

    /* 创建report body */
    p_st_report_body = informix_new_report_body(p_st_conn, p_st_private->p_st_sess);
    /* 创建report body失败时，不释放做成的request */
    if (p_st_report_body == NULL)
    {
        frdbg("create report  failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 上报resposne数据 */
    i_ret = frdb_report_resp2(p_st_conn, p_st_hash_report, p_st_statement
                             , p_st_resultset, p_st_resp->i_error_num
                             , p_st_resp->p_error_msg
                             , p_st_resp->p_error_msg, &p_st_report_body);
    /* 上报request数据失败时，不释放做成的request */
    if (i_ret != FR_SUCC)
    {
        frdbg("frdb_report_resp2 failed!\n");
        frreport_body_free(&p_st_report_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 初始化resultset */
    frdb_init_resultset(p_st_req->p_st_resultset, frct_seq_increase(p_st_conn));
    /* 销毁request和response数据 */
    informix_destroy_request(&p_st_private->p_st_req);
    informix_destroy_response(&p_st_private->p_st_resp);
    return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
}

/*******************************************************************************
*  FUNC     :  解析LOGIN响应
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_login_resp(Conntrack *p_st_conn
                             , L7session_informix_private *p_st_private)
{
    uint8_t u8_count = 0;
    uint16_t u16_login_len = 0;
    uint16_t u16_len = 0;
    uint16_t u16_error = 0;
    uint16_t u16_env_count = 0;
    uint32_t u32_cap1 = 0;
    uint32_t u32_cap2 = 0;
    uint32_t u32_cap3 = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    L7_fragment_informix *p_st_fragment = p_st_private->p_st_fragment;
    Frbyte_Packet *p_st_data = p_st_fragment->p_st_data;
    Frreport_data *p_st_report_data=NULL;
    char arr_info[128] = {0};

    /* Get login length */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_login_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < INFORMIX_HEADER_SIZE)
    {
        frdbg("Call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 3;
    bytebuff_get_char(p_st_data, &u8_count);
    if (u8_count == 2 || u8_count == 3)
    {
        u16_login_len -= 3;
        bytebuff_skip(p_st_data, 3);
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("parse login resposne failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        /* 加密 */
        if (u16_len == 110)
        {
            return APM_L7_ANALYZE_SUCC;
        }
        else if (u16_len != 100)
        {
            frdbg("parse login resposne failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }

        i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("parse login resposne failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        if (u16_len != 101)
        {
            frdbg("parse login resposne failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        u16_login_len -= 4;
    }
    else
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* skip 4bytes */
    i_ret = bytebuff_skip(p_st_data, 4);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 4;
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_ret = bytebuff_skip(p_st_data, u16_len);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2 + u16_len;

    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_len != 108)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2;

    /* skip 12bytes */
    i_ret = bytebuff_skip(p_st_data, 12);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 12;

    /* skip VersionNumber */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_ret = bytebuff_skip(p_st_data, u16_len);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2 + u16_len;

    /* skip SerialNumber */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_ret = bytebuff_skip(p_st_data, u16_len);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2 + u16_len;

    /* skip ApplidName */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_ret = bytebuff_skip(p_st_data, u16_len);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2 + u16_len;

    /* get cap1 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_cap1, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 4;
    /* get cap2 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_cap2, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 4;
    /* get cap3 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_cap3, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 4;

    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_ret = bytebuff_skip(p_st_data, u16_len);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2 + u16_len;

    i_ret = bytebuff_skip(p_st_data, 2);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2;

    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_ret = bytebuff_skip(p_st_data, u16_len);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2 + u16_len;

    i_ret = bytebuff_skip(p_st_data, 24);
    if (i_ret != FR_SUCC)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 24;

    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
    {
        frdbg("parse login resposne failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    u16_login_len -= 2;

    if (u16_len == 102)
    {
        i_ret = bytebuff_skip(p_st_data, 6);
        if (i_ret != FR_SUCC)
        {
            frdbg("parse login resposne failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        u16_login_len -= 6;
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_error, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC || u16_login_len < 2 + u16_len)
        {
            frdbg("parse login resposne failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        u16_login_len -= 2;

        i_ret = bytebuff_skip(p_st_data, 2 + 2);
        if (i_ret != FR_SUCC)
        {
            frdbg("parse login resposne failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        u16_login_len -= 2 + 2;

        /* skip env */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_env_count, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Parse Login reuqest failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        while (u16_env_count--)
        {
            i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
            if (i_ret != FR_SUCC || u16_login_len < u16_len + 2)
            {
                frdbg("Parse Login reuqest failed!\n");
                return APM_L7_ANALYZE_FAIL;
            }
            u16_login_len -= u16_len + 2;
            bytebuff_skip(p_st_data, u16_len);
            i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
            if (i_ret != FR_SUCC || u16_login_len < u16_len + 2)
            {
                frdbg("Parse Login reuqest failed!\n");
                return APM_L7_ANALYZE_FAIL;
            }
            u16_login_len -= u16_len + 2;
            bytebuff_skip(p_st_data, u16_len);
        }
    }

    if (p_st_sess->p_db_user)
    {
        snprintf(arr_info, sizeof(arr_info), "%s login", p_st_sess->p_db_user);
    }
    else
    {
        snprintf(arr_info, sizeof(arr_info), "login");
    }
    /* 有一部分反编译出来缺失 todo */
    if (u16_error == 0)
    {
       p_st_sess->st_login = p_st_fragment->st_first_timestamp;
       p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGON, arr_info, &p_st_fragment->st_first_timestamp);
    }
    else
    {
        p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGON_REJECT, arr_info, &p_st_fragment->st_first_timestamp);
    }
    if (p_st_report_data)
    {
        i_ret = frreport_send(g_p_apm_context, &p_st_report_data);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }
    }

    if (u32_cap1 && u32_cap1 != 316)
    {
        p_st_sess->arr_ver_info[INFORMIX_903_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_902_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_USVER_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;

        if (u32_cap1 >= 315)
        {
            p_st_sess->arr_ver_info[INFORMIX_DESCRIBEINPUTSUPPORTED_IDX] = 1;
            p_st_sess->arr_ver_info[INFORMIX_IDX10_IDX] = 1;
            p_st_sess->arr_ver_info[INFORMIX_9301_IDX] = 1;
            p_st_sess->arr_ver_info[INFORMIX_90303_IDX] = 1;
        }
        else if (u32_cap1 >= 304)
        {
            p_st_sess->arr_ver_info[INFORMIX_IDX10_IDX] = 1;
            p_st_sess->arr_ver_info[INFORMIX_9301_IDX] = 1;
            p_st_sess->arr_ver_info[INFORMIX_90303_IDX] = 1;
        }
        else if (u32_cap1 >= 303)
        {
            p_st_sess->arr_ver_info[INFORMIX_9301_IDX] = 1;
            p_st_sess->arr_ver_info[INFORMIX_90303_IDX] = 1;
        }
        else if (u32_cap1 >= 301)
        {
            p_st_sess->arr_ver_info[INFORMIX_90303_IDX] = 1;
        }
        else
        {
            memset(p_st_sess->arr_ver_info, 0x0, sizeof(p_st_sess->arr_ver_info));
        }
    }

    informix_destroy_curr_info(p_st_private);
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析DESCRIBE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_describe(Conntrack *p_st_conn
                           , L7session_informix_private *p_st_private)
{
    int i_ret = FR_SUCC;
    uint16_t u16_rows = 0;
    uint16_t u16_last_len = 0;
    uint32_t u32_last_len = 0;
    uint16_t u16_data_type = 0;
    uint32_t u32_encoded_len = 0;
    uint16_t u16_statement_id = 0;
    uint16_t u16_statement_type = 0;
    uint32_t u32_ret3 = 0;
    int i_data_type = 0;
    int i_nullable_flg = FR_NO;
    unsigned int ui_skip_len = 0;
    unsigned int ui_last_len = 0;
    unsigned int ui_precision = 0;
    unsigned int ui_scale = 0;
    unsigned int ui_len = 0;
    Frlist_node *p_st_node = NULL;
    Sql_metadata_info *p_st_metadata = NULL;
    L7_resp_informix *p_st_resp = p_st_private->p_st_resp;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 长度check */
    if (bytebuff_remaining(p_st_data) < 2 + 2 + 4 + 2 + 2 + 4)
    {
        frdbg("Need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    /* get statementType */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_statement_type, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* get statementID */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_statement_id, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得error3 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_ret3, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Call bytebuff_get_int failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* skip TupleSize */
    bytebuff_skip(p_st_data, 2);
    /* get cloum row count */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_rows, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得结尾长度 */
    if (p_st_sess->arr_ver_info[INFORMIX_4BYTEOFFSETSUPPORTED_IDX])
    {
        i_ret = bytebuff_get_int(p_st_data, 4, &u32_last_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call bytebuff_get_int failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        ui_last_len = u32_last_len;
    }
    else
    {
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_last_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call bytebuff_get_int failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        ui_last_len = u16_last_len;
    }

    while (u16_rows--)
    {
        ui_skip_len = 2;
        if (p_st_sess->arr_ver_info[INFORMIX_4BYTEOFFSETSUPPORTED_IDX])
        {
            ui_skip_len += 2;
        }
        ui_skip_len += 2;
        if (p_st_sess->arr_ver_info[INFORMIX_USVER_IDX])
        {
            ui_skip_len += 2;
        }
        i_ret = informix_skip_bytes(p_st_data, ui_skip_len);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            frdbg("skip bytes failed!\n");
            return i_ret;
        }

        /* get sql type */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_data_type, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            frdbg("get sql type failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        if ((u16_data_type & 0x100) > 0)
        {
           i_nullable_flg = FR_YES;
        }
        i_data_type = u16_data_type & (0x00FF);


        if (bytebuff_remaining(p_st_data) < 4)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            frdbg("Need more data!\n");
            return APM_L7_ANALYZE_TODO;
        }
        /* skip */
        bytebuff_skip(p_st_data, 4);
        /* skip ExtendedId and ExtendedOwnerName */
        i_ret = informix_skip_2byte_padded(p_st_data);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            frdbg("Call informix_skip_2byte_padded failed!\n");
            return i_ret;
        }
        i_ret = informix_skip_2byte_padded(p_st_data);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            frdbg("Call informix_skip_2byte_padded failed!\n");
            return i_ret;
        }
        /* skip source type */
        if (bytebuff_remaining(p_st_data) < 2 + 2 + 4 + 4)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            frdbg("Need more data!\n");
            return APM_L7_ANALYZE_TODO;
        }
        bytebuff_skip(p_st_data, 2 + 2 + 4);
        /* get Encoded Length  */
        i_ret = bytebuff_get_int(p_st_data, 4, &u32_encoded_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column
                              , frdb_metadata_node_free);
            frdbg("Call bytebuff_get_int failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        switch (i_data_type)
        {
            case INFORMIX_TYPE_DECIMAL:
            case INFORMIX_TYPE_MONEY:
                ui_precision = u32_encoded_len >> 8 & 0xFF;
                ui_scale = u32_encoded_len & 0xFF;

            case INFORMIX_TYPE_DATETIME:
            case INFORMIX_TYPE_INTERVAL:
                ui_len = ((u32_encoded_len >> 8 & 0xFF)
                         + (u32_encoded_len & 0xFF & 0x1) + 3) / 2;
                break;

            default:
                ui_len = u32_encoded_len;
                break;
        }

        /* 创建节点 */
        p_st_metadata = (Sql_metadata_info *)frmalloc(sizeof(Sql_metadata_info));
        if (p_st_metadata == NULL)
        {
            frlist_remove_all(&p_st_resp->st_metadata_column, frdb_metadata_node_free);
            return APM_L7_ANALYZE_FAIL;
        }
        memset(p_st_metadata, 0x0, sizeof(Sql_metadata_info));
        p_st_metadata->i_data_type = i_data_type;
        p_st_metadata->ui_precision = ui_precision;
        p_st_metadata->ui_scale = ui_scale;
        p_st_metadata->ui_len = ui_len;
        p_st_metadata->i_isnullbydescribe = i_nullable_flg;
        p_st_node = frlist_node_create(p_st_metadata);
        if (p_st_node == NULL)
        {
            frfree(p_st_metadata);
            frlist_remove_all(&p_st_resp->st_metadata_column, frdb_metadata_node_free);
            return APM_L7_ANALYZE_FAIL;
        }
        frlist_push(&p_st_resp->st_metadata_column, p_st_node);
    }

    /* skip last data */
    i_ret = informix_skip_padded(p_st_data, ui_last_len);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frlist_remove_all(&p_st_resp->st_metadata_column
                          , frdb_metadata_node_free);
        frdbg("Call informix_skip_padded failed!\n");
        return i_ret;
    }

    /* 设置cursor id */
    p_st_resp->arr_ret[3] = (int)u32_ret3;
    p_st_resp->i_statement_type = u16_statement_type;
    p_st_resp->l_cursor_id = u16_statement_id;
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析ERROR
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_err_resp(Conntrack *p_st_conn
                            , L7session_informix_private *p_st_private)
{
    uint16_t u16_sqlcode = 0;
    uint16_t u16_ret1 = 0;
    uint16_t u16_ret4 = 0;
    uint32_t u32_ret4 = 0;
    short s_sqlcode = 0;
    char *p_err_msg = NULL;
    unsigned int ui_size = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_resp_informix *p_st_resp = p_st_private->p_st_resp;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 长度check */
    if (bytebuff_remaining(p_st_data) < 2)
    {
        frdbg("Need more length!\n");
        return APM_L7_ANALYZE_TODO;
    }
    /* 取得sqlcode */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_sqlcode, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    s_sqlcode = (short)u16_sqlcode;
    if (s_sqlcode == -619)
    {
        i_ret = informix_skip_bytes(p_st_data,  2 * 2);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip bytes failed!\n");
            return i_ret;
        }
        if (p_st_sess->arr_ver_info[INFORMIX_REMOVE64KLIMITSUPPORTED_IDX])
        {
            i_ret = informix_skip_bytes(p_st_data,  2 * 1);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                return i_ret;
            }
        }
        i_ret = informix_skip_2byte_padded(p_st_data);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip padded failed!\n");
            return i_ret;
        }

        /* 设置error */
        p_st_resp->i_error_num = s_sqlcode;
        return APM_L7_ANALYZE_SUCC;
    }

    if (p_st_sess->arr_ver_info[INFORMIX_REMOVE64KLIMITSUPPORTED_IDX])
    {
        /* 长度check */
        if (bytebuff_remaining(p_st_data) < 2 + 4)
        {
            frdbg("Need more length!\n");
            return APM_L7_ANALYZE_TODO;
        }
        /* 取得sqlcode */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_ret1, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call bytebuff_get_short failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }

        /* 取得sqlcode */
        i_ret = bytebuff_get_int(p_st_data, 4, &u32_ret4, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call bytebuff_get_short failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_resp->arr_ret[1] = u16_ret1;
        p_st_resp->arr_ret[4] = (int)u32_ret4;

    }
    else
    {
        /* 长度check */
        if (bytebuff_remaining(p_st_data) < 2 + 2)
        {
            frdbg("Need more length!\n");
            return APM_L7_ANALYZE_TODO;
        }
        /* 取得sqlcode */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_ret1, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call bytebuff_get_short failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }

        /* 取得sqlcode */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_ret4, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call bytebuff_get_short failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_resp->arr_ret[1] = u16_ret1;
        p_st_resp->arr_ret[4] = u16_ret4;
    }

    if (s_sqlcode != -368)
    {
        /* 取得error message */
        i_ret = informix_get_2byte_padded(p_st_data, &p_err_msg, &ui_size);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("call informix_get_2byte_padded failed!\n");
            return i_ret;
        }
    }

    //if (s_sqlcode == 0 && p_st_sess->arr_resp_db_ver[18] == 0)
    if (s_sqlcode == 0)
    {
        frfree(p_err_msg);
        p_st_resp->i_error_num = -407;
    }
    else if (s_sqlcode == 100) //warning
    {
        //p_st_resp->i_error_num = 100;
        frfree(p_err_msg);
        p_st_resp->i_error_num = 0; //当做正常
    }
    else if (s_sqlcode != 0 && s_sqlcode != -937)
    {
        i_ret = informix_merge_string(p_st_resp->p_error_msg
                                     , p_err_msg, &p_st_resp->p_error_msg);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("set error message failed!\n");
            frfree(p_err_msg);
            return i_ret;
        }
        p_st_resp->i_error_num = s_sqlcode;
    }
    else
    {
        i_ret = informix_skip_padded(p_st_data, 5);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("call informix_skip_padded failed!\n");
            return i_ret;
        }
        /* 取得error message */
        i_ret = informix_get_2byte_padded(p_st_data, &p_err_msg, &ui_size);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("call informix_get_2byte_padded failed!\n");
            return i_ret;
        }
        if (s_sqlcode == 0)
        {
            frfree(p_err_msg);
        }
        else
        {
            i_ret = informix_merge_string(p_st_resp->p_error_msg
                                         , p_err_msg, &p_st_resp->p_error_msg);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("call informix_merge_string failed!\n");
                frfree(p_err_msg);
                return i_ret;
            }
            p_st_resp->i_error_num = s_sqlcode;
        }
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析TUPLE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_tuple(Conntrack *p_st_conn
                         , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_resp_informix *p_st_resp = p_st_private->p_st_resp;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* skip first 2byte */
    i_ret = informix_skip_bytes(p_st_data, 2);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("Skip bytes failed!\n");
        return i_ret;
    }
    /* skip padded */
    if (p_st_sess->arr_ver_info[INFORMIX_USVER_IDX])
    {
        i_ret = informix_skip_4byte_padded(p_st_data);
    }
    else
    {
        i_ret = informix_skip_2byte_padded(p_st_data);
    }
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("Skip padded failed!\n");
        return i_ret;
    }

    p_st_resp->ui_fetch_rows += 1;
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析DONE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_done(Conntrack *p_st_conn
                       , L7session_informix_private *p_st_private)
{
    uint32_t u32_ret1 = 0;
    uint32_t u32_ret2 = 0;
    uint32_t u32_ret5 = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_resp_informix *p_st_resp = p_st_private->p_st_resp;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 长度check */
    if (bytebuff_remaining(p_st_data) < 2 + 4 + 4 + 4)
    {
        return APM_L7_ANALYZE_TODO;
    }
    /* skip warning */
    bytebuff_skip(p_st_data, 2);
    /* 取得error2 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_ret2, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得error2 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_ret5, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得error2 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_ret1, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 设置return code */
    p_st_resp->arr_ret[1] = (int)u32_ret1;
    p_st_resp->arr_ret[2] = (int)u32_ret2;
    p_st_resp->arr_ret[5] = (int)u32_ret5;
    p_st_resp->i_done_flg = FR_YES;
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析puterr
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_puterr(Conntrack *p_st_conn
                         , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 长度check */
    i_ret = informix_skip_bytes(p_st_data, 4);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("Call informix_skip_bytes failed!\n");
        return i_ret;
    }

    i_ret = informix_parse_err_resp(p_st_conn, p_st_private);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("Call informix_parse_err failed!\n");
        return i_ret;
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析TUPID
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_tupid(Conntrack *p_st_conn
                         , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 长度check */
    i_ret = informix_skip_bytes(p_st_data, 4);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip bytes failed!\n");
        return i_ret;
    }
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析DBLIST
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_dblist_resp(Conntrack *p_st_conn
                               , L7session_informix_private *p_st_private)
{
    uint16_t u16_len = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    while (1)
    {
        /* 长度check */
        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("Need more data!\n");
            return APM_L7_ANALYZE_TODO;
        }
        /* get db length */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call bytebuff_get_short failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        if (u16_len != 0)
        {
            i_ret = informix_skip_padded(p_st_data, u16_len);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("Call bytebuff_get_short failed!\n");
                return i_ret;
            }
        }
        else
        {
            break;
        }
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析BLOB
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_blob_resp(Conntrack *p_st_conn
                            , L7session_informix_private *p_st_private)
{
    int i_ret = FR_SUCC;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    i_ret = informix_skip_2byte_padded(p_st_data);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip padded failed!\n");
        return i_ret;
    }
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析VERSION
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_version(Conntrack *p_st_conn
                          , L7session_informix_private *p_st_private)
{
    char *p_version = NULL;
    unsigned int ui_size = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 取得version */
    i_ret = informix_get_2byte_padded(p_st_data, &p_version, &ui_size);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("call informix_get_2byte_padded failed!\n");
        return i_ret;
    }
    memset(p_st_sess->arr_ver_info, 0x0, sizeof(p_st_sess->arr_ver_info));

    if (strcmp(p_version, "9.03") == 0)
    {
        p_st_sess->arr_ver_info[INFORMIX_903_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_902_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_USVER_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if (strcmp(p_version,"9.02") >= 0)
    {
        p_st_sess->arr_ver_info[INFORMIX_902_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_USVER_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if (strcmp(p_version,"9.00") >= 0)
    {
        p_st_sess->arr_ver_info[INFORMIX_USVER_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if (strcmp(p_version,"8.40") >= 0)
    {
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_XPSVER8_40_IDX] = 1;
    }
    else if (strcmp(p_version,"8.20") >= 0)
    {
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if (strcmp(p_version,"8.10") >= 0)
    {
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
    }
    else if ((strcmp(p_version,"7.31") >= 0) && (strcmp(p_version,"7.z") <= 0))
    {
        p_st_sess->arr_ver_info[INFORMIX_4BYTEOFFSETSUPPORTED_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_IDX9_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        //p_st_sess->arr_ver_info[INFORMIX_IDX6_IDX] = 1;
        //p_st_sess->arr_ver_info[INFORMIX_IDX1_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if ((strcmp(p_version,"7.30") >= 0) && (strcmp(p_version,"7.z") <= 0))
    {
        p_st_sess->arr_ver_info[INFORMIX_IDX9_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        //p_st_sess->arr_ver_info[INFORMIX_IDX6_IDX] = 1;
        //p_st_sess->arr_ver_info[INFORMIX_IDX1_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if ((strcmp(p_version,"7.24") >= 0) && (strcmp(p_version,"7.z") <= 0))
    {
        memset(p_st_sess->arr_ver_info, 0x0, sizeof(p_st_sess->arr_ver_info));
    }
    else if ((strcmp(p_version,"7.23") >= 0) && (strcmp(p_version,"7.z") <= 0))
    {
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        //p_st_sess->arr_ver_info[INFORMIX_IDX6_IDX] = 1;
        //p_st_sess->arr_ver_info[INFORMIX_IDX1_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if ((strcmp(p_version,"7.22") >= 0) && (strcmp(p_version,"7.z") <= 0))
    {
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        //p_st_sess->arr_ver_info[INFORMIX_IDX1_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if ((strcmp(p_version,"7.20") >= 0) && (strcmp(p_version,"7.z") <= 0))
    {
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;
    }
    else if (strcmp(p_version,"7.00") >= 0)
    {
        p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
    }
    else if (strcmp(p_version,"6.00") >= 0)
    {
        p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
    }
    else
    {
        memset(p_st_sess->arr_ver_info, 0x0, sizeof(p_st_sess->arr_ver_info));
    }

    frfree(p_version);
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析COST
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_cost(Conntrack *p_st_conn
                       , L7session_informix_private *p_st_private)
{
    uint32_t u32_ret0 = 0;
    uint32_t u32_ret3 = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_resp_informix *p_st_resp = p_st_private->p_st_resp;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 长度check */
    if (bytebuff_remaining(p_st_data) < 4 + 4)
    {
        frdbg("Need more length!\n");
        return APM_L7_ANALYZE_TODO;
    }
    /* 取得error index */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_ret0, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Call bytebuff_get_int failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得error code */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_ret3, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Call bytebuff_get_int failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 设置return code */
    p_st_resp->arr_ret[0] = (int)u32_ret0;
    p_st_resp->arr_ret[3] = (int)u32_ret3;
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析INFO
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_info_resp(Conntrack *p_st_conn
                            , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    uint16_t u16_type = 0;
    uint16_t u16_value = 0;
    unsigned int ui_value = 0;
    unsigned int ui_value5 = 0;
    short s_type = 0;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    while (1)
    {
        /* 长度check */
        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("Need more length!\n");
            return APM_L7_ANALYZE_TODO;
        }
        /* 取得error index */
        i_ret = bytebuff_get_short(p_st_data, 4, &u16_type, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get type failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        s_type = (short)u16_type;
        if (s_type <= 0)
        {
            break;
        }
        /* 长度check */
        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("Need more length!\n");
            return APM_L7_ANALYZE_TODO;
        }
        /* 取得error index */
        i_ret = bytebuff_get_short(p_st_data, 4, &u16_value, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get type failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        ui_value = u16_value;

        switch (s_type)
        {
            case 2:
                break;

            case 3:
            case 4:
                ui_value5 = 0;
                while (1)
                {
                    if (ui_value5 >= ui_value/4)
                    {
                        break;
                    }
                    i_ret = informix_skip_bytes(p_st_data, 4);
                    if (i_ret != APM_L7_ANALYZE_SUCC)
                    {
                        frdbg("skip bytes failed!\n");
                        return i_ret;
                    }
                }
                break;

            default:
                i_ret = informix_skip_padded(p_st_data, ui_value);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    frdbg("skip bytes failed!\n");
                    return i_ret;
                }
        }
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析INSERTDONE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_insertdone(Conntrack *p_st_conn
                              , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    if (p_st_sess->arr_ver_info[INFORMIX_BIGINTSUPPORTED_IDX])
    {
        i_ret = informix_skip_bytes(p_st_data, 8 + 10);
    }
    else
    {
        i_ret = informix_skip_bytes(p_st_data, 10);
    }
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("Call bytebuff_get_int failed!\n");
        return i_ret;
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析LODATA
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_lodata_resp(Conntrack *p_st_conn
                              , L7session_informix_private *p_st_private)
{
    uint16_t u16_len = 0;
    uint32_t u32_count = 0;
    int i_count = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_fragment_informix *p_st_fragment = p_st_private->p_st_fragment;
    Frbyte_Packet *p_st_data = p_st_fragment->p_st_data;

    /* check长度是否足够 */
    if (bytebuff_remaining(p_st_data) < 2 + 4)
    {
        frdbg("Need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    /* 取得长度 */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_count, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_count = (int)u32_count;

    if (u16_len == 2)
    {
        return APM_L7_ANALYZE_SUCC;
    }

    if (i_count < 1)
    {
        i_ret = informix_skip_bytes(p_st_data, 2);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip bytes failed!\n");
            return i_ret;
        }
        return APM_L7_ANALYZE_SUCC;
    }

    /* TODO this.BlobRequestSize > i_count */
    while (i_count--)
    {
        i_ret = informix_skip_2byte_padded(p_st_data);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip padded failed!\n");
            return i_ret;
        }
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析FILE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_file(Conntrack *p_st_conn
                       , L7session_informix_private *p_st_private)
{
    uint16_t u16_type = 0;
    uint16_t u16_len = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* check长度是否足够 */
    if (bytebuff_remaining(p_st_data) < 2)
    {
        frdbg("Need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_type, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    switch (u16_type)
    {
        case 0:
            i_ret = informix_skip_2byte_padded(p_st_data);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("Call informix_skip_2byte_padded failed!\n");
                return i_ret;
            }
            i_ret = informix_skip_bytes(p_st_data, 4 + 4 + 4 + 2);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("Call informix_skip_2byte_padded failed!\n");
                return i_ret;
            }
            break;

        case 2:
            i_ret = informix_skip_bytes(p_st_data, 2 + 4 + 2);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("Call informix_skip_2byte_padded failed!\n");
                return i_ret;
            }
            break;

        case 3:
            /* check长度是否足够 */
            if (bytebuff_remaining(p_st_data) < 2)
            {
                frdbg("Need more data!\n");
                return APM_L7_ANALYZE_TODO;
            }
            /* 取得长度 */
            i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
            if (i_ret != FR_SUCC)
            {
                frdbg("call bytebuff_get_short failed!\n");
                return APM_L7_ANALYZE_FAIL;
            }
            while (u16_len != 12)
            {
                i_ret = informix_skip_2byte_padded(p_st_data);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    frdbg("Call informix_skip_2byte_padded failed!\n");
                    return i_ret;
                }
                /* check长度是否足够 */
                if (bytebuff_remaining(p_st_data) < 2)
                {
                    frdbg("Need more data!\n");
                    return APM_L7_ANALYZE_TODO;
                }
                /* 取得长度 */
                i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
                if (i_ret != FR_SUCC)
                {
                    frdbg("call bytebuff_get_short failed!\n");
                    return APM_L7_ANALYZE_FAIL;
                }
            }
            if (u16_len == 13)
            {
                i_ret = informix_skip_bytes(p_st_data, 2);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    frdbg("Call informix_skip_2byte_padded failed!\n");
                    return i_ret;
                }
            }
            break;

        case 1:
            i_ret = informix_skip_bytes(p_st_data, 2);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("Call informix_skip_2byte_padded failed!\n");
                return i_ret;
            }
            break;

        default:
            break;
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析xactstat
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_xactstat(Conntrack *p_st_conn
                           , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    i_ret = informix_skip_bytes(p_st_data, 2 + 2 + 2);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip bytes failed!\n");
        return i_ret;
    }
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析BEGIN/COMMIT/ROLLBACK/GetDBList之类共通的没有数据的MESSAGE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_idescribe(Conntrack *p_st_conn
                             , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    i_ret = informix_parse_describe_comm(p_st_private, FR_NO);
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  解析GETROUTINE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_getroutine_resp(Conntrack *p_st_conn
                                  , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    if (p_st_sess->arr_ver_info[INFORMIX_NAMEDPARAMETERSSUPPORTED_IDX])
    {
        i_ret = informix_skip_2byte_padded(p_st_data);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip padded failed!\n");
            return i_ret;
        }
    }

    i_ret = informix_skip_bytes(p_st_data, 4);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip bytes failed!\n");
        return i_ret;
    }
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析FPROUTINE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_fproutine(Conntrack *p_st_conn
                            , L7session_informix_private *p_st_private)
{
    uint16_t u16_count = 0;
    uint16_t u16_distinct = 0;
    uint16_t u16_flg = 0;
    uint16_t u16_len = 0;
    int i_is_distinct = FR_NO;
    int i_sql_type = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    if (bytebuff_remaining(p_st_data) < 2)
    {
        frdbg("need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    /* 取得bind参数个数 */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_count, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("get conut failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    while (u16_count--)
    {
        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("need more data!\n");
            return APM_L7_ANALYZE_TODO;
        }
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_distinct, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get distinct failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        i_is_distinct = FR_NO;
        if ((u16_distinct & 0x800) > 0)
        {
            i_is_distinct = FR_YES;
        }
        i_sql_type = u16_distinct & 0x00FF;

        if ((i_sql_type >= 18 && i_sql_type != INFORMIX_TYPE_BIGINT
            && i_sql_type != INFORMIX_TYPE_BIGSERIAL )|| i_is_distinct == FR_YES)
        {
            i_ret = informix_skip_2byte_padded(p_st_data);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip padded failed!\n");
                return i_ret;
            }
            i_ret = informix_skip_2byte_padded(p_st_data);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip padded failed!\n");
                return i_ret;
            }
        }
        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("need more data!\n");
            return APM_L7_ANALYZE_TODO;
        }
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_flg, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get flag failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("need more data!\n");
            return APM_L7_ANALYZE_TODO;
        }
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get length failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        if (u16_flg != 0xFFFF)
        {
            switch (i_sql_type)
            {
                case INFORMIX_TYPE_CHAR:      // 0
                case INFORMIX_TYPE_VARCHAR:   //13
                case INFORMIX_TYPE_NCHAR:     //15
                case INFORMIX_TYPE_NVCHAR:    //16
                case INFORMIX_TYPE_DECIMAL:   //5
                case INFORMIX_TYPE_MONEY:     //8
                case INFORMIX_TYPE_INTERVAL:  //14
                case INFORMIX_TYPE_DATETIME:  //10
                    i_ret = informix_skip_2byte_padded(p_st_data);
                    break;

                case INFORMIX_TYPE_INT:       //2
                case INFORMIX_TYPE_SERIAL:    //6
                case INFORMIX_TYPE_DATE:      //7
                case INFORMIX_TYPE_SMFLOAT:   //4
                    i_ret = informix_skip_bytes(p_st_data, 4);
                    break;

                case INFORMIX_TYPE_SMALLINT:  //1
                    i_ret = informix_skip_bytes(p_st_data, 2);
                    break;

                case INFORMIX_TYPE_INT8:      //17
                case INFORMIX_TYPE_SERIAL8:   //18
                case INFORMIX_TYPE_FLOAT:     //3
                    i_ret = informix_skip_bytes(p_st_data, 8);
                    break;

                case INFORMIX_TYPE_BIGINT:
                case INFORMIX_TYPE_BIGSERIAL:
                    i_ret = informix_skip_bytes(p_st_data, 10);
                    break;

                case INFORMIX_TYPE_UDTVAR:     //40
                case INFORMIX_TYPE_UDTFIXED:   //41
                case INFORMIX_TYPE_SENDRECV:   //44
                    i_ret = informix_skip_4byte_padded(p_st_data);
                    break;

                case INFORMIX_TYPE_SET:        //19
                case INFORMIX_TYPE_MULTISET:   //20
                case INFORMIX_TYPE_LIST:       //21
                case INFORMIX_TYPE_ROW:        //22
                    if (bytebuff_remaining(p_st_data) < 2)
                    {
                        return APM_L7_ANALYZE_TODO;
                    }
                    bytebuff_skip(p_st_data, 2);
                    i_ret = informix_skip_4byte_padded(p_st_data);
                    break;

                default:
                    frdbg("Type [%d]unsupport!\n", i_sql_type);
                    i_ret = APM_L7_ANALYZE_SUCC;
                    break;
            }
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                return i_ret;
            }
        }
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析FPARAM
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_fparam(Conntrack *p_st_conn
                          , L7session_informix_private *p_st_private)
{
    int i_ret = FR_SUCC;
    uint16_t u16_rets = 0;
    uint16_t u16_args = 0;
    uint16_t u16_flg = 0;
    int i_bool_flg = FR_NO;
    L7_resp_informix *p_st_resp = p_st_private->p_st_resp;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    i_ret = informix_skip_bytes(p_st_data, 8 + 4 + 1);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip bytes failed!\n");
        return i_ret;
    }
    if (p_st_resp->i_fparam_flg)
    {
        return APM_L7_ANALYZE_SUCC;
    }
    i_ret = informix_skip_bytes(p_st_data, 4 + 8 + 4);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip bytes failed!\n");
        return i_ret;
    }

    if (bytebuff_remaining(p_st_data) < 2)
    {
        frdbg("need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_rets, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("get returns failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    if (u16_rets > 0)
    {
        i_ret = __informix_skip_type_info(p_st_private, u16_rets
                                          , FR_NO, FR_NO);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("Call __informix_skip_type_info failed!\n");
            return i_ret;
        }
    }

    if (bytebuff_remaining(p_st_data) < 2)
    {
        frdbg("need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_args, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Call bytebuff_get_short failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    if (p_st_sess->arr_ver_info[INFORMIX_NAMEDPARAMETERSSUPPORTED_IDX])
    {
        if (bytebuff_remaining(p_st_data) < 2)
        {
            frdbg("need more data!\n");
            return APM_L7_ANALYZE_TODO;
        }
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_flg, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Call bytebuff_get_short failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        if (u16_flg & 0x01)
        {
            i_bool_flg = FR_YES;
        }
    }

    if (u16_args > 0)
    {
        i_ret = __informix_skip_type_info(p_st_private, u16_args, FR_YES, i_bool_flg);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("Call __informix_skip_type_info failed!\n");
            return i_ret;
        }
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析protocols
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_protocols_resp(Conntrack *p_st_conn
                                 , L7session_informix_private *p_st_private)
{
    int i_ret = FR_SUCC;
    uint16_t u16_len = 0;
    unsigned int ui_loop = 0;
    int i_index = 0;
    unsigned int ui_size = 0;
    unsigned int ui_cli_len = 0;
    unsigned char uc_param = 0;
    char *p_output = NULL;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* check长度是否足够 */
    if (bytebuff_remaining(p_st_data) < 2)
    {
        frdbg("Need more length!\n");
        return APM_L7_ANALYZE_TODO;
    }
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("get length failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得protocols */
    i_ret = informix_read_padded(p_st_data, u16_len, &p_output, &ui_size);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("get protocols failed!\n");
        return i_ret;
    }
    /* clear 源设置 */
    memset(p_st_sess->arr_ver_info, 0x0, sizeof(p_st_sess->arr_ver_info));
    p_st_sess->arr_ver_info[INFORMIX_903_IDX] = 1;
    p_st_sess->arr_ver_info[INFORMIX_902_IDX] = 1;
    p_st_sess->arr_ver_info[INFORMIX_USVER_IDX] = 1;
    p_st_sess->arr_ver_info[INFORMIX_CURSESSINFO_IDX] = 1;
    p_st_sess->arr_ver_info[INFORMIX_ASF_IDX] = 1;
    p_st_sess->arr_ver_info[INFORMIX_GLS_IDX] = 1;

    ui_cli_len = p_st_sess->ui_req_ver_size;
    while (ui_loop < ui_cli_len)
    {
        uc_param = (unsigned char)p_output[ui_loop];
        if ((uc_param & 0x80) > 0)
        {
            switch (i_index)
            {
                case 8:
                    p_st_sess->arr_ver_info[INFORMIX_90303_IDX] = 1;
                    break;

                case 0:
                case 16:
                case 24:
                case 32:
                case 40:
                case 48:
                    break;

                case 56:
                    p_st_sess->arr_ver_info[INFORMIX_SAVEPOINTSUPPORTED_IDX] = 1;
                    break;

                default:
                    frdbg("Please attention unsupport version!\n");
                    break;
            }
        }
        i_index++;

        if ((uc_param & 0x40) > 0)
        {
            switch (i_index)
            {
                case 1:
                    break;

                case 9:
                    p_st_sess->arr_ver_info[INFORMIX_IDX9_IDX] = 1;
                    break;

                case 17:
                case 25:
                case 33:
                case 41:
                case 49:
                case 57:
                    break;

                default:
                    frdbg("Please attention unsupport version!\n");
                    break;
            }
        }
        i_index++;

        if ((uc_param & 0x20) > 0)
        {
            switch (i_index)
            {
                case 2:
                    p_st_sess->arr_ver_info[INFORMIX_USVER_IDX] = 1;
                    break;

                case 10:
                    p_st_sess->arr_ver_info[INFORMIX_IDX10_IDX] = 1;
                    break;

                case 18:
                    p_st_sess->arr_ver_info[INFORMIX_IDX18_IDX] = 1;
                    break;

                case 34:
                    p_st_sess->arr_ver_info[INFORMIX_DESCRIBEINPUTSUPPORTED_IDX] = 1;
                    break;

                case 50:
                    p_st_sess->arr_ver_info[INFORMIX_4BYTEOFFSETSUPPORTED_IDX] = 1;
                    break;

                case 26:
                case 42:
                case 58:
                    break;

                default:
                    frdbg("Please attention unsupport version!\n");
                    break;
            }
        }
        i_index++;

        if ((uc_param & 0x10) > 0)
        {
            switch (i_index)
            {
                case 3:
                    p_st_sess->arr_ver_info[INFORMIX_902_IDX] = 1;
                    break;

                case 11:
                case 19:
                case 27:
                case 35:
                case 43:
                case 51:
                    break;

                case 59:
                    p_st_sess->arr_ver_info[INFORMIX_PRIVATESERVERENABLED_IDX] = 1;
                    break;

                default:
                    frdbg("Please attention unsupport version!\n");
                    break;
            }
        }
        i_index++;

        if ((uc_param & 0x8) > 0)
        {
            switch (i_index)
            {
                case 4:
                    p_st_sess->arr_ver_info[INFORMIX_903_IDX] = 1;
                    break;

                case 12:
                case 20:
                case 28:
                case 60:
                    break;

                case 36:
                    p_st_sess->arr_ver_info[INFORMIX_MULTIPLEUDROUTSUPPORTED_IDX] = 1;
                    break;

                case 44:
                    p_st_sess->arr_ver_info[INFORMIX_PAMAUTHENTICATION_IDX] = 1;
                    break;

                case 52:
                    p_st_sess->arr_ver_info[INFORMIX_NAMEDPARAMETERSSUPPORTED_IDX] = 1;
                    break;

                default:
                    frdbg("Please attention unsupport version!\n");
                    break;
            }
        }
        i_index++;

        if ((uc_param & 0x4) > 0)
        {
            switch (i_index)
            {
                case 5:
                    p_st_sess->arr_ver_info[INFORMIX_9301_IDX] = 1;
                    break;

                case 13:
                case 21:
                case 29:
                case 45:
                case 53:
                    break;

                case 37:
                    p_st_sess->arr_ver_info[INFORMIX_LVCGTTHAN2KSUPPORTED_IDX] = 1;
                    break;

                case 61:
                    p_st_sess->arr_ver_info[INFORMIX_SQBATCHSUPPORTED_IDX] = 1;
                    break;

                default:
                    frdbg("Please attention unsupport version!\n");
                    break;
            }
        }
        i_index++;

        if ((uc_param & 0x2) > 0)
        {
            switch (i_index)
            {
                case 6:
                case 14:
                case 22:
                case 30:
                case 38:
                case 46:
                    break;

                case 54:
                    p_st_sess->arr_ver_info[INFORMIX_BIGINTSUPPORTED_IDX] = 1;
                    break;

                case 62:
                    p_st_sess->arr_ver_info[INFORMIX_REMOVE64KLIMITSUPPORTED_IDX] = 1;
                    break;

                default:
                    frdbg("Please attention unsupport version!\n");
                    break;
            }
        }
        i_index++;

        if ((uc_param & 0x1) > 0)
        {
            switch (i_index)
            {
                case 7:
                case 15:
                case 23:
                case 31:
                case 39:
                case 47:
                case 55:
                    break;

                case 63:
                    p_st_sess->arr_ver_info[INFORMIX_2GBFETCHBUFFERSUPPORTED_IDX] = 1;
                    break;

                default:
                    frdbg("Please attention unsupport version!\n");
                    break;
            }
        }
        i_index++;
        ui_loop++;
    }

    frfree(p_output);
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析IFPDESCRIBE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_ifpdescribe(Conntrack *p_st_conn
                              , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    i_ret = informix_parse_describe_comm(p_st_private, FR_YES);
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  解析FPARAM
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_accept(Conntrack *p_st_conn
                          , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* 长度check */
    i_ret = informix_skip_bytes(p_st_data, 2);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("Call informix_skip_bytes failed!\n");
        return i_ret;
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析SGKDESCRIBE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_sgkdescribe(Conntrack *p_st_conn
                               , L7session_informix_private *p_st_private)
{

    int i_ret = APM_L7_ANALYZE_SUCC;
    uint16_t u16_len = 0;
    uint32_t u32_len = 0;
    uint16_t u16_count = 0;
    uint32_t u32_ret3 = 0;
    unsigned int ui_last_len = 0;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    /* skip 4bytes */
    i_ret = informix_skip_bytes(p_st_data, 2 + 2);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip bytes failed!\n");
        return i_ret;
    }

    /* get return code3 */
    if (bytebuff_remaining(p_st_data) < 4 + 2 + 2 + 2)
    {
        frdbg("Need more length!\n");
        return APM_L7_ANALYZE_TODO;
    }
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_ret3, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("get return code failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    bytebuff_skip(p_st_data, 2);
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_count, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("get count failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 版本未定猜测设置版本,一般sql不会超过65536 */
    if (p_st_sess->i_ver_get_flg == FR_NO)
    {
        i_ret = bytebuff_peek_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("get length failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        if (u16_len == 0)
        {
            p_st_sess->arr_ver_info[INFORMIX_4BYTEOFFSETSUPPORTED_IDX] = 1;
        }
    }

    /* 4byte长度 */
    if (p_st_sess->arr_ver_info[INFORMIX_4BYTEOFFSETSUPPORTED_IDX])
    {
        if (bytebuff_remaining(p_st_data) < 4)
        {
            frdbg("Need more length!\n");
            return APM_L7_ANALYZE_TODO;
        }
        i_ret = bytebuff_get_int(p_st_data, 4, &u32_len, BYTE_BIG_ENDIAN);
        ui_last_len = u32_len;
    }
    else
    {
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
        ui_last_len = u16_len;
    }
    if (i_ret != FR_SUCC)
    {
        frdbg("get length failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    while (u16_count--)
    {
        if (p_st_sess->arr_ver_info[INFORMIX_4BYTEOFFSETSUPPORTED_IDX])
        {
            i_ret = informix_skip_bytes(p_st_data, 4);
        }
        else
        {
            i_ret = informix_skip_bytes(p_st_data, 2);
        }
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("skip bytes failed!\n");
            return i_ret;
        }

        if (p_st_sess->arr_ver_info[INFORMIX_USVER_IDX])
        {
            i_ret = informix_skip_bytes(p_st_data, 4 + 2 + 4);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                return i_ret;
            }
            i_ret = informix_skip_2byte_padded(p_st_data);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip padded failed!\n");
                return i_ret;
            }
            i_ret = informix_skip_2byte_padded(p_st_data);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip padded failed!\n");
                return i_ret;
            }
            i_ret = informix_skip_bytes(p_st_data, 2 + 2 + 4 + 4);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                return i_ret;
            }
        }
        else
        {
            i_ret = informix_skip_bytes(p_st_data, 2 + 2 + 2);
            if (i_ret != APM_L7_ANALYZE_SUCC)
            {
                frdbg("skip bytes failed!\n");
                return i_ret;
            }
        }
    }

    i_ret = informix_skip_padded(p_st_data, ui_last_len);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip padded failed!\n");
        return i_ret;
    }
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析SGKTUPLE
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_sgktuple(Conntrack *p_st_conn
                           , L7session_informix_private *p_st_private)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_informix *p_st_sess = p_st_private->p_st_sess;
    Frbyte_Packet *p_st_data = p_st_private->p_st_fragment->p_st_data;

    i_ret = informix_skip_bytes(p_st_data, 2);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip bytes failed");
        return i_ret;
    }
    if (p_st_sess->arr_ver_info[INFORMIX_USVER_IDX])
    {
        i_ret = informix_skip_4byte_padded(p_st_data);
    }
    else
    {
        i_ret = informix_skip_2byte_padded(p_st_data);
    }
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("skip padded failed!\n");
        return i_ret;
    }
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析TOKENIZED TDS REQUEST
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
int informix_parse_response(Conntrack *p_st_conn
                           , L7session_informix_private *p_st_private
                           , Frhash_header *p_st_hash_report)
{
    uint16_t u16_2byte_head = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_resp_informix *p_st_resp = NULL;
    L7_req_informix *p_st_req = p_st_private->p_st_req;
    L7_fragment_informix *p_st_fragment = p_st_private->p_st_fragment;
    Frbyte_Packet *p_st_data = p_st_fragment->p_st_data;

    if (p_st_fragment->i_need_req_resp == INFORMIX_DIRECT_REQUEST)
    {
        frdbg("Thers is a request before!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 创建response */
    if (p_st_private->p_st_resp == NULL)
    {
        p_st_private->p_st_resp = (L7_resp_informix *)frmalloc(sizeof(L7_resp_informix));
        if (p_st_private->p_st_resp == NULL)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        /* 初始化response */
        memset(p_st_private->p_st_resp, 0x0, sizeof(L7_resp_informix));
    }
    p_st_resp = p_st_private->p_st_resp;

    bytebuff_setPosition(p_st_data, p_st_fragment->ui_parsed_index);
    /* 取得头部两位的值 */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_2byte_head, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    while (u16_2byte_head != INFORMIX_MSG_TP_EOT)
    {
        switch(u16_2byte_head)
        {
            case INFORMIX_MSG_TP_DESCRIBE: //(0x08)8
                i_ret = informix_parse_describe(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_ERR:  //(0x0D)13
                i_ret = informix_parse_err_resp(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_TUPLE: //(0x0E)14
                i_ret = informix_parse_tuple(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_DONE: //(0x0F)15
                i_ret = informix_parse_done(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_PUTERR: //(0x12)18
                i_ret = informix_parse_puterr(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_TUPID:  //(0x19)25
                i_ret = informix_parse_tupid(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_DBLIST:  //(0x20)26
                i_ret = informix_parse_dblist_resp(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_BLOB:   //(0x27)39
                i_ret = informix_parse_blob_resp(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_VERSION:  //(0x35)53
                i_ret = informix_parse_version(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_COST: //(0x37)55
                i_ret = informix_parse_cost(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_EXIT:  //(0x38)56
                p_st_resp->i_resp_type = u16_2byte_head; /* 关闭连接 */
                i_ret = APM_L7_ANALYZE_SUCC;
                break;

            case INFORMIX_MSG_TP_INFO:  //(0x51)81
                i_ret = informix_parse_info_resp(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_INSERTDONE: //(0x5E)94
                i_ret = informix_parse_insertdone(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_LODATA:  //(61)97
                i_ret = informix_parse_lodata_resp(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_FILE:   //(62)98
                i_ret = informix_parse_file(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_XACTSTAT:  //(63)99
                i_ret = informix_parse_xactstat(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_GETROUTINE: //(65)101
                i_ret = informix_parse_getroutine_resp(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_FPROUTINE: //(67)103
                i_ret = informix_parse_fproutine(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_FPARAM: //(68)104
                i_ret = informix_parse_fparam(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_IDESCRIBE: //(0x7D)125
                i_ret = informix_parse_idescribe(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_PROTOCOLS: //(0x7E)126
                i_ret = informix_parse_protocols_resp(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_IFPDESCRIBE:
                i_ret = informix_parse_ifpdescribe(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_ACCEPT:
                i_ret = informix_parse_accept(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_SGKDESCRIBE:
                i_ret = informix_parse_sgkdescribe(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_SGKTUPLE:
                i_ret = informix_parse_sgktuple(p_st_conn, p_st_private);
                break;

            case INFORMIX_MSG_TP_DESCBIND: //todo
            case INFORMIX_MSG_TP_XCLOSE:
            case INFORMIX_MSG_TP_XEND:
            case INFORMIX_MSG_TP_CLOSE:
            case INFORMIX_MSG_TP_REASSOC:
                i_ret = APM_L7_ANALYZE_SUCC;
                break;

            default:
                frdbg("unsupport message type:[%d] faied!\n", u16_2byte_head);
                i_ret = APM_L7_ANALYZE_FAIL;
                break;
        }

        /* 解析结果处理 */
        if (i_ret == APM_L7_ANALYZE_SUCC)
        {
            p_st_fragment->ui_parsed_index = bytebuff_getPosition(p_st_data);
        }
        else if (i_ret == APM_L7_ANALYZE_TODO)
        {
            frdbg("Parse token:[%d] need more data!\n", u16_2byte_head);
            return APM_L7_ANALYZE_TODO;
        }
        else
        {
            frdbg("Parse token:[%d] faied!\n", u16_2byte_head);
            return APM_L7_ANALYZE_FAIL;
        }

        /* 取得下一个token值 */
        if (bytebuff_remaining(p_st_data) < 2)
        {
            return APM_L7_ANALYZE_TODO;
        }
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_2byte_head, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            frdbg("Parse response faied!\n");
            return APM_L7_ANALYZE_FAIL;
        }
    }

    /* EOT作为结束token, 必须出现在末尾 */
    if (bytebuff_remaining(p_st_data) == 0)
    {
        /* 更新数据 */
        if (p_st_req->p_st_resultset)
        {
            if (p_st_req->i_req_type == INFORMIX_MSG_TP_NFETCH)
            {
                i_ret = frdb_set_resultset_resp2(p_st_req->p_st_resultset
                                                , bytebuff_length(p_st_data)
                                                , 1
                                                , &p_st_resp->ui_fetch_rows
                                                , &(p_st_fragment->st_first_timestamp)
                                                , &(p_st_fragment->st_end_timestamp));
            }
            else
            {
                p_st_resp->ui_effect_rows = p_st_resp->arr_ret[2];
                i_ret = frdb_set_resultset_resp2(p_st_req->p_st_resultset
                                                , bytebuff_length(p_st_data)
                                                , 1
                                                , &p_st_resp->ui_effect_rows
                                                , &(p_st_fragment->st_first_timestamp)
                                                , &(p_st_fragment->st_end_timestamp));
            }
            if (i_ret != FR_SUCC)
            {
                frdbg("set resultset failed!\n");
                return APM_L7_ANALYZE_FAIL;
            }
        }
        /* 初始化 */
        informix_init_fragment(p_st_fragment);

        /* 上报数据 */
        if (p_st_resp->i_error_num)
        {
            i_ret = __informix_report_resp(p_st_conn, p_st_private
                                          , p_st_hash_report);
            return i_ret;
        }

        /* 根据request type上报数据 */
        switch (p_st_req->i_req_type)
        {
            /* 追加到hash */
            case INFORMIX_MSG_TP_PREPARE:
                /* add statement to hash with arr_id */
                p_st_req->i_req_type = 0;
                i_ret = informix_add_statement(p_st_private);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    frdbg("add statement failed!\n");
                    return APM_L7_ANALYZE_FAIL;
                }
                return APM_L7_ANALYZE_SUCC;

            case INFORMIX_MSG_TP_NFETCH:
            case INFORMIX_MSG_TP_SFETCH:
                p_st_req->i_req_type = 0;
                if (p_st_resp->i_done_flg == FR_YES)
                {
                    i_ret = __informix_report_resp(p_st_conn, p_st_private
                                                  , p_st_hash_report);
                    return i_ret;
                }
                return APM_L7_ANALYZE_SUCC;

            /* 需要上报request数据 */
            case INFORMIX_MSG_TP_COMMAND:
            case INFORMIX_MSG_TP_EXECUTE:
            case INFORMIX_MSG_TP_BEGIN:
            case INFORMIX_MSG_TP_DBLIST:
            case INFORMIX_MSG_TP_XCOMMIT:
            case INFORMIX_MSG_TP_XROLLBACK:
            case INFORMIX_MSG_TP_PUT:
                p_st_req->i_req_type = 0;
                i_ret = __informix_report_resp(p_st_conn, p_st_private
                                              , p_st_hash_report);
                return i_ret;

            default:
                p_st_req->i_req_type = 0;
                i_ret = APM_L7_ANALYZE_SUCC;
                break;
        }
        return i_ret;
    }
    else
    {
        frdbg("Parse request failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
}
